package edu.uci.ics.ai.maze.models;

import edu.uci.ics.ai.maze.controllers.SearchContext;
import java.util.ArrayList;
import java.util.Observable;
import java.util.logging.Logger;

public class GameModel extends Observable {

  private static final Logger logger = Logger.getLogger(GameModel.class.getName());
  private static final SearchResult NO_RESULT = new SearchResult(null, new ArrayList<Vertex>(), 0, 0);
  private static final Maze NO_MAZE = new Maze(null, null, new ArrayList<Polygon>());
  private final SearchContext context;
  //maze's attributes
  private Maze maze;
  private int mazeScaleFactor;
  private SearchAlgorithm currentAlgorithm;
  private SearchResult searchResult;

  public GameModel() {
    context = new SearchContext(this);
    resetState();
  }

  /**
   * Returns the SearchResult from the last run.
   *
   * @return the SearchResult
   */
  public SearchResult getSearchResult() {
    return searchResult;
  }

  /**
   * Sets the SearchResult.
   *
   * @param result the result to set
   */
  public void setSearchResult(SearchResult result) {
    this.searchResult = result;
  }

  /**
   * Returns the currently selected algorithm.
   *
   * @return the running algorithm
   */
  public SearchAlgorithm getAlgorithm() {
    return currentAlgorithm;
  }

  /**
   * @param algorithm the algorithm to set
   */
  public void setAlgorithm(SearchAlgorithm algorithm) {
    this.currentAlgorithm = algorithm;
    resetPath();
  }

  /**
   * Returns the context for SearchAlgorithm implementers.
   * 
   * @return the context
   */
  public SearchContext getContext() {
    return context;
  }

  public Maze getMaze() {
    return maze;
  }

  public void setMaze(Maze maze) {
    this.maze = maze;
  }

  /**
   * Returns the Maze scale factor.
   *
   * @return the mazeScaleFactor
   */
  public int getScaleFactor() {
    return mazeScaleFactor;
  }

  /**
   * @param mazeScaleFactor the scaleFactor to set
   */
  public void setScaleFactor(int mazeScaleFactor) {
    this.mazeScaleFactor = mazeScaleFactor;
  }

  public void clear() {
    resetState();
    setChanged();
    notifyObservers(Observations.UPDATE_MAZE);
  }

  private void resetState() {
    maze = NO_MAZE;
    setSearchResult(NO_RESULT);
    setScaleFactor(1);
  }

  public void resetPath() {
    setSearchResult(NO_RESULT);
    setChanged();
  }

  public static enum Observations {

    UPDATE_VISIBLE_VERTICES,
    UPDATE_MAZE,
    UPDATE_VIS_VERTEX_DIALOG,
    UPDATE_PATH
  }
}
